//
//  pkGraphView.m
/*
 Copyright 2009 Jack Whitsitt
 Conact: sintixerr@gmail.com | http://sintixerr.wordpress.com
 
 This file is part of "pkviz".
 
 "pkviz" is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 "pkviz" is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with "pkviz".  If not, see <http://www.gnu.org/licenses/>.
 */ 

#define YLOG 0
#define MAKERECT 0
#define PIXELSIZE 5
#define MAXLAYERS 1000000
#define LAYERSTODISPLAY 30
#define MARGIN 5 // this will prolly go away

#import "pkGraphView.h"

@implementation pkGraphView

@synthesize winSizeField;
@synthesize headersExpanded;

- (void)drawRect:(NSRect)dirtyRect // Set background of graph to black
{ 	
	// fill self with white
    NSRect bounds = [self bounds];
	[[NSColor blackColor] set];
	[NSBezierPath fillRect:bounds];
}



- (id)initWithFrame:(NSRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) 
	{
		layd = [[layerDelegate alloc] init]; // create layer delegate. this handles the drawing for our layers
		onePacketMode = 0;
		windowSize = LAYERSTODISPLAY;
		last_kp = 0;
		kp = 0;
	}

    return self;
}



- (IBAction)manualWindowSize:(id)sender // Button Action to Set Animation Depth Here
{
	int new_ws = [winSizeField intValue];
		
	if (new_ws < windowSize)
	{
		int new_oldest_layer = (kp-new_ws);
		int remove = 0;
		
		if (kp >= windowSize)
		{
			remove = (kp - windowSize)+1;
		}
		else 
		{
			remove = 0;
		}

		while (remove <= new_oldest_layer) 
		{
			[[layers objectAtIndex:(remove)] removeFromSuperlayer];
			++remove;
		}
		
		[self setWindowSize:new_ws];

	}
	else if (new_ws > windowSize)
	{
		[self setWindowSize:new_ws];

	}
}



- (void) setupLayers // transformData class should prep the layers before rendering
{
	layers = [NSMutableArray arrayWithCapacity:MAXLAYERS];
	[layers retain];
	
	layerWindow = [NSMutableArray arrayWithCapacity:windowSize];
	[layerWindow retain];
}



- (void) setWindowSize:(int)ws; // this is a function in case we have to do something else here later
{
	windowSize = ws;
}



- (void) removeLayers //this used to be used to try and clear layers at end of stream, 
//but transformData doesnt appear to use it any more
{
	[[self layer] setSublayers:nil];
	layers = nil;	
}



- (void) removeThisPacket:(int)pknum // forward and back animations auto remove, but jumps need to specify a layer/packet to remove
{
	[[layers objectAtIndex:pknum] removeFromSuperlayer];
	
}



- (void) moveOneFrameForward:(NSArray *)packet withKp:(int)pkiter //transform data will run this as many times as needed. pkiter = current/key packet
{
	last_kp = kp; 
	kp = pkiter; // kp is current/key packet
	
	int leftWindow = 0; // leftwindow is the leftmost/oldest packet that should be viewable from keypacket back for any depth/windowsize specified
	
	if (kp >= (windowSize-1)) // leftwindow stays at 0 until we're bigger than our window
	{
		leftWindow = (kp+1) - windowSize;
	}

	
	if (kp >= [layers count]) // if we havent created a layer for this packet yet, create it.  
	{
		//each layer gets mapped to layerDelegate which will handle the creation of a path to be plotted for each layer/packet
		// "layers" is an array which keeps the layers we've made - whether or not theyre current attached to a view or visible...
		
		CALayer *layer = [CALayer layer];
		
		CGRect b_maybemybounds = [[self layer] bounds];
		b_maybemybounds = CGRectInset(b_maybemybounds, MARGIN, MARGIN);
		[layer setAnchorPoint:CGPointMake(0, 0)];
		[layer setFrame:b_maybemybounds];
		
		[layer setDelegate:layd]; // setting current layer's delegate...delagate does the drawing/path stuff
		
		[layers addObject:layer]; // add layer to my own index to track them. 
		
		[layd readyNextPacket:packet withIter:kp andLayerCount: windowSize andHeadersExpanded:[[self headersExpanded] intValue]]; // we should make delegate have a drawing function not tied to del func
		
		[layer setOpacity:0];
		
//		[layer display]; // commentthis out, we display later !!!!!!!!!!!!!!!!!
		
	}
	
	
	[[self layer] addSublayer:[layers objectAtIndex:kp]]; // add layer to view stack

	
	if ((windowSize > 1) && (kp > (windowSize - 1))) // remove layers/packets earlier than our current window allows.
	{
		[[layers objectAtIndex:(leftWindow - 1)] removeFromSuperlayer];
	}
	
	else //need to use a different algorithm is windowsize is 1...
	{
		[[layers objectAtIndex:kp-1] removeFromSuperlayer];

	}
	
	//**** HERE WE'RE CHANGING TRANSPARENCY/ALPHA VALUES OF LAYERS AS THEY GET OLDER...SO NEWEST LAYER BRIGHT, OLDEST BARELY VISIBLE
	int lw = leftWindow;
	int lc = 0;
	float alph = 0;
	
	
	if (lw < kp)
	{
		while (lw <= kp) 
		{
			alph = .1+((.9/windowSize)*lc);
			
			[[layers objectAtIndex:lw] setOpacity:alph];
			
			++lc;
			++lw;
		}
	}
	else 
	{
		[[layers objectAtIndex:kp] setOpacity:1];
	}

	//**********
	
	
	
	[[layers objectAtIndex:kp] display]; // go ahead and tell view to display the new layer. the other layers may or may not update at same time, we dont care
		
}

- (void) moveOneFrameBack:(NSArray *)packet withKp:(int)pkiter
{
	
	last_kp = kp;
	kp = pkiter;
	
	int leftWindow = 0;
	
	if (kp >= (windowSize-1)) // leftwindow stays at 0 until we're bigger than our window
	{
		leftWindow = (kp+1) - windowSize;
	}
	
	if (leftWindow > 0) 
	{
		[[self layer] addSublayer:[layers objectAtIndex:kp]]; // add layer to view stack
	}

	[[layers objectAtIndex:kp+1] removeFromSuperlayer];

	int lw = leftWindow;
	int lc = 0;
	float alph = 0;
	
	if (lw < kp)
	{
		while (lw <= kp) 
		{
			alph = .1+((.9/windowSize)*lc);
			
			[[layers objectAtIndex:lw] setOpacity:alph];
			
			++lc;
			++lw;
		}
	}
	else 
	{
		[[layers objectAtIndex:kp] setOpacity:1];
	}
	
	[[layers objectAtIndex:kp] display];
}


@end

